using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TileEngine;

namespace TileEngine
{
    public class MenuScreen
    {
        public Dictionary<int, MenuItem> items = new Dictionary<int, MenuItem>();
        int id;
        string name;

        public int ID
        {
            get { return this.id; }
        }

        public string Name
        {
            get { return this.name; }
        }

        public MenuScreen(int id, string name)
        {
            this.id = id;
            this.name = name;
        }
    }

    public class MenuItem
    {
        string id;
        string name;
        string action;

        public string ID
        {
            get { return this.id; }
        }

        public string Name
        {
            get { return this.name; }
        }

        public string Action
        {
            get { return this.action; }
        }

        public MenuItem(string id, string name, string action)
        {
            this.id = id;
            this.name = name;
            this.action = action;
        }
    }

    public class Menu : DrawableGameComponent
    {
        public const string AudioSettings = @"Audio\Sounds.xgs";
        public const string AudioWaveBank = @"Audio\WaveBank.xwb";
        public const string AudioSoundsBank = @"Audio\SoundBank.xsb";
        public string ScreenTitle = "Mr Explosions";
        Map map;
        Audio music;

        Dictionary<int, MenuScreen> menus = new Dictionary<int, MenuScreen>();
        List<Character> characters = new List<Character>();
        List<Bomb> bombs = new List<Bomb>();

        SpriteBatch spriteBatch;
        KeyboardState oldState;
        Texture2D background;
        SpriteFont titleFont;
        SpriteFont defaultFont;
        int currentMenuItem;
        string currentMenuSelect = "0";
        int maxChildren;
        string selectedMap;
        int selection = 1;
        bool sound = true;
        bool effects = true;
        string numPlayers;

        public Menu(string file, Game game)
            : base(game)
        {
            file = this.Game.Content.RootDirectory + @"\" + file;

            if (!File.Exists(file))
            {
                throw new IOException("Cannot find file: " + file);
            }

            XmlTextReader xmlReader = null;
            XmlDocument xmlDocument;

            try
            {
                xmlReader = new XmlTextReader(file);
                xmlDocument = new XmlDocument();
                xmlDocument.Load(xmlReader);

                XmlNodeList menu = xmlDocument.GetElementsByTagName("menu");

                for (int i = 0; i < menu.Count; i++)
                {
                    XmlNodeList children = menu[i].ChildNodes;
                    XmlAttributeCollection attribs = menu[i].Attributes;

                    this.menus.Add(i, new MenuScreen(Int32.Parse(attribs["id"].InnerText), attribs["name"].InnerText));

                    for (int n = 0; n < children.Count; n++)
                    {
                        this.menus[i].items.Add(n, new MenuItem(children[n].Attributes["id"].InnerText, children[n].InnerText, children[n].Attributes["action"].InnerText));
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (xmlReader != null)
                {
                    xmlReader.Close();
                }
            }
        }

        public override void Initialize()
        {
            base.Initialize();

            this.oldState = Keyboard.GetState();
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            this.spriteBatch = (SpriteBatch)this.Game.Services.GetService(typeof(SpriteBatch));

            this.background = this.Game.Content.Load<Texture2D>(@"Sprites\Menu");
            this.defaultFont = this.Game.Content.Load<SpriteFont>(@"Fonts\Adore64-18pt");
            this.titleFont = this.Game.Content.Load<SpriteFont>(@"Fonts\Adore64-24pt");
        }

        public void StartGame()
        {
            this.map = new Map(@"Maps\" + this.selectedMap + ".xml", this.Game);
            this.Game.Components.Add(this.map);

            this.ScreenTitle += " - " + this.map.Name;
            this.Game.Window.Title = this.ScreenTitle;

            this.music = new Audio("Menu", AudioSettings, AudioWaveBank, AudioSoundsBank, this.Game);
            this.Game.Components.Add(this.music);

            if (this.sound)
            {
                //Add sound
            }

            if (this.effects)
            {
                //Add effects
            }

            Controls controls1 = new Controls();
            controls1.Up = Keys.W;
            controls1.Down = Keys.S;
            controls1.Left = Keys.A;
            controls1.Right = Keys.D;
            controls1.Drop = Keys.Q;

            Controls controls2 = new Controls();
            controls2.Up = Keys.I;
            controls2.Down = Keys.K;
            controls2.Left = Keys.J;
            controls2.Right = Keys.L;
            controls2.Drop = Keys.U;

            this.characters.Add(new Character(this.map, controls1, 17, @"Sprites\White", this.Game, this.characters));
            this.Game.Components.Add(this.characters[0]);

            this.characters.Add(new Character(this.map, controls2, 29, @"Sprites\Green", this.Game, this.characters));
            this.Game.Components.Add(this.characters[1]);

            if (this.numPlayers == "3 players" || this.numPlayers == "4 players")
            {
                Controls controls3 = new Controls();
                controls3.Up = Keys.Up;
                controls3.Down = Keys.Down;
                controls3.Left = Keys.Left;
                controls3.Right = Keys.Right;
                controls3.Drop = Keys.RightControl;

                this.characters.Add(new Character(this.map, controls3, 167, @"Sprites\Red", this.Game, this.characters));
                this.Game.Components.Add(this.characters[2]);

                if (this.numPlayers == "4 players")
                {
                    Controls controls4 = new Controls();
                    controls4.Up = Keys.NumPad8;
                    controls4.Down = Keys.NumPad2;
                    controls4.Left = Keys.NumPad4;
                    controls4.Right = Keys.NumPad6;
                    controls4.Drop = Keys.NumPad0;

                    this.characters.Add(new Character(this.map, controls4, 179, @"Sprites\Black", this.Game, this.characters));
                    this.Game.Components.Add(this.characters[3]);
                }
            }
        }

        public override void Update(GameTime gameTime)
        {
            KeyboardState newState = Keyboard.GetState();

            if (!newState.IsKeyDown(Keys.Up))
            {
                if (this.oldState.IsKeyDown(Keys.Up))
                {
                    this.currentMenuItem--;
                }
            }

            if (!newState.IsKeyDown(Keys.Down))
            {
                if (this.oldState.IsKeyDown(Keys.Down))
                {
                    this.currentMenuItem++;
                }
            }

            if (this.currentMenuItem < 0)
            {
                this.currentMenuItem = 0;
            }

            if (this.currentMenuItem > (this.maxChildren - 1))
            {
                this.currentMenuItem = this.maxChildren - 1;
            }

            if (!newState.IsKeyDown(Keys.Enter))
            {
                if (this.oldState.IsKeyDown(Keys.Enter))
                {
                    switch (this.currentMenuSelect)
                    {
                        case "quit":
                            this.Game.Exit();
                            break;
                        case "options":
                            this.selection = 6;
                            break;
                        case "credits":
                            this.selection = 6;
                            break;
                        case "startGame":
                            this.Game.Components.Remove(this);
                            this.StartGame();
                            break;
                        case "sound":
                            this.effects = !this.effects;
                            break;
                        case "music":
                            this.sound = !this.sound;
                            break;
                        default:
                            this.selection = Int32.Parse(this.currentMenuSelect);
                            break;
                    }

                    this.currentMenuItem = 0;
                }
            }

            this.oldState = newState;

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            this.spriteBatch.Draw(this.background, new Rectangle(0, 0, this.background.Width, this.background.Height), Color.White);

            int vertical = 200;
            int selected = 0;

            foreach (KeyValuePair<int, MenuScreen> entry in this.menus)
            {
                if (entry.Value.ID == selection)
                {
                    this.maxChildren = entry.Value.items.Count;

                    this.spriteBatch.DrawString(this.titleFont, entry.Value.Name, new Vector2(this.Game.Window.ClientBounds.Width / 2, 130) - (this.titleFont.MeasureString(entry.Value.Name) / 2), Color.Red);

                    foreach (KeyValuePair<int, MenuItem> menuText in entry.Value.items)
                    {
                        if (selected == this.currentMenuItem)
                        {
                            this.spriteBatch.DrawString(this.defaultFont, menuText.Value.Name, new Vector2(this.Game.Window.ClientBounds.Width / 2, vertical) - (this.defaultFont.MeasureString(menuText.Value.Name) / 2), Color.Yellow);

                            this.currentMenuSelect = menuText.Value.Action;
                            this.selectedMap = menuText.Value.Name;

                            if (this.currentMenuSelect == "3")
                            {
                                this.numPlayers = menuText.Value.Name;
                            }
                        }
                        else
                        {
                            this.spriteBatch.DrawString(this.defaultFont, menuText.Value.Name, new Vector2(this.Game.Window.ClientBounds.Width / 2, vertical) - (this.defaultFont.MeasureString(menuText.Value.Name) / 2), Color.White);
                        }

                        selected++;
                        vertical += 50;
                    }
                }
            }
        }
    }
}
